/*
    SEL - Simple DirectMedia Layer Extension Library
    Copyright (C) 2001 Matej Knopp <knopp@users.sf.net>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public
    License along with this library; if not, write to the Free
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
*/

#ifndef __sel_surface_h__
#define __sel_surface_h__

#include "sdl.h"
#include "object.h"
#include "rect.h"
#include "rwops.h"
#include "videoinfo.h"

namespace SEL {

//! The graphical surface class.
/*!
 The SEL::Surface class represents areas of "graphical" memory, memory that
 can be drawn to. Most of surface properties are read only. To access the
 video framebuffer use the SEL::Surface::pixels () function. Make sure that
 you lock the surface before accessing the framebuffer. (This applies only
 to hardware surfaces and RLE compressed surfaces). Each surface has a
 pixel format associated with it. The pixel format specifies how the
 pixels are arranged in the frame buffer. The surface has also flags that
 specify the kind of the surface.
 \sa pixels (), flags (), lock (), unlock (), mustLock ()
 */
class Surface : public Object
{
public:
        //! Create a new surface by wrapping an existing SDL::Surface.
	/*!
	  If \a wrap_me is NULL, an exception is thrown.
	  \warning Do not free the \a wrap_me surface before the wrapper
	  is freed, because it may lead to a crash.
	  \param wrap_me the SDL::Surface to be wrapped.
	  \param auto_free whether to free the wrapped surface on wrapper's
	  destruction.
	 */
        Surface (SDL::Surface *wrap_me, bool auto_free = true);

        //! Standard destructor.
        /*!
          \warning You shouldn't delete this object directly. Instead
          of that consider calling the unref member function.

          \sa unref ()
         */
        virtual ~Surface ();

        //! \name Access to surface internals.
        //@{

	//! Get the wrapped SDL::Surface structure.
        SDL::Surface *surface () 		{ return m_surface; }

	//! Get the wrapped constant SDL::Surface structure.
        const SDL::Surface *surface () const	{ return m_surface; }

	//! Get the surface's flags.
	/*!
	  The flags are OR'd following values:
	  \verbatim
	  SDL::SWSURFACE  Surface is stored in system memory
	  SDL::HWSURFACE  Surface is stored in video memory
	  SDL::ASYNCBLIT  Surface uses asynchronous blits if possible
	  SDL::ANYFORMAT  Allows any pixel-format (Display surface)
	  SDL::HWPALETTE  Surface has exclusive palette
	  SDL::DOUBLEBUF  Surface is double buffered (Display surface)
	  SDL::FULLSCREEN Surface is full screen (Display Surface)
	  SDL::OPENGL     Surface has an OpenGL context (Display Surface)
	  SDL::OPENGLBLIT Surface supports OpenGL blitting (Display Surface)
	  SDL::RESIZABLE  Surface is resizable (Display Surface)
	  SDL::HWACCEL    Surface blit uses hardware acceleration
	  SDL::SRCOLORKEY Surface use colorkey blitting
	  SDL::RLEACCEL   Colorkey blitting is accelerated with RLE
	  SDL::SRCALPHA   Surface blit uses alpha blending
	  SDL::PREALLOC   Surface uses preallocated memory
	  \endverbatim
	 */
        Uint32 flags ()	const		{ return m_surface->flags; }

        //! Return the pixel format of the surface.
	/*!
	  For more information about the SDL::PixelFormat structure
	  consult the SDL documentation.
	 */
        SDL::PixelFormat *format () 	{ return m_surface->format; }

        //! Return the pixel format of the surface.
	/*!
	  For more information about the SDL::PixelFormat structure
	  consult the SDL documentation.
	 */
        const SDL::PixelFormat *format () const
					{ return m_surface->format; }

        //! Return the width of the surface.
        int w () const			{ return m_surface->w; }

        //! Return the height of the surface.
        int h () const			{ return m_surface->h; }

        //! Return the scanline width in bytes.
        Uint16 pitch () const		{ return m_surface->pitch; }

        //! Return the pointer to the framebuffer data.
	/*!
	  \warning If the surface is stored in video memory or it's
	  a RLE comressed surface you must call the SEL::Surface::lock ()
	  function before accessing the framebuffer and the
	  SEL::Surface::unlock () afterwards. To determine, whether the
	  surface needs locking or not, you can use the SEL::Surface::mustLock ()
	  member function.

	  The structure of pixels in framebuffer is stored in the pixel format.
	  \sa lock (), unlock (), mustLock (), format ()
	 */
        void *pixels () 		{ return m_surface->pixels; }

        //! Return the const pointer to the framebuffer data.
	/*!
	  \warning If the surface is stored in video memory or it's
	  a RLE comressed surface you must call the SEL::Surface::lock ()
	  function before accessing the framebuffer and the
	  SEL::Surface::unlock () afterwards. To determine, whether the
	  surface needs locking or not, you can use the SEL::Surface::mustLock ()
	  member function.

	  The structure of pixels in framebuffer is stored in the pixel format.
	  \sa lock (), unlock (), mustLock (), format ()
	 */
        const void *pixels () const	{ return m_surface->pixels; }

        //@}

        //! Get the parent of the surface.
	/*!
	  The surface has a parent only if it's a child surface (e.g. it's
	  a part of parent surface).
	  \return The pointer to the parent surface, or NULL if none.
	  \sa createChildSurface ()
	 */
	Surface *parent () 		{ return m_parent; }

        //! Get the parent of the surface.
	/*!
	  The surface has a parent only if it's a child surface (e.g. it's
	  a part of parent surface).
	  \return The pointer to the parent surface, or NULL if none.
	  \sa createChildSurface ()
	 */
	const Surface *parent () const	{ return m_parent; }

        //! \name Surface creation
        //@{
        //! Allocate an empty RGB surface.
	/*!
	  \warning This must be called after a display surface is created.

	  If the depth is 4 or 8 bit, an empty palette is allocated for the
	  surface. If the depth is greater than 8 bits, the pixel format is
	  set using the masks.

	  If it runs out of memory, it will throw an exception.

	  The \a flags tell what kind of surface to create.
          - SDL::SWSURFACE means that the surface should be created in
	  system memory.
          - SDL::HWSURFACE means that the surface should be created in
	  video memory, with the same format as the display surface.
	  This is useful for surfaces that will not change much, to
	  take advantage of hardware acceleration when being blitted
	  to the display surface.
          - SDL::ASYNCBLIT means that SDL will try to perform asynchronous
	  blits with this surface, but you must always lock it before accessing
	  the pixels. SDL will wait for current blits to finish before returning
	  from the lock.
	  - SDL::SRCCOLORKEY indicates that the surface will be used for
	  colorkey blits. If the hardware supports acceleration of colorkey
	  blits between two surfaces in video memory, SDL will try to place
	  the surface in video memory. If this isn't possible or if there
	  is no hardware acceleration available, the surface will be placed
	  in system memory.
	  - SDL::SRCALPHA means that the surface will be used for alpha blits
	  and if the hardware supports hardware acceleration of alpha blits
	  between two surfaces in video memory, to place the surface in video
	  memory if possible, otherwise it will be placed in system memory.
	  If the surface is created in video memory, blits will be much
	  faster, but the surface format must be identical to the video
	  surface format, and the only way to access the pixels member of the
	  surface is to use the SEL::Surface::lock() and SEL::Surface::unlock()
	  calls.

	  If the requested surface actually resides in video memory,
	  SDL::HWSURFACE will be set in the flags member of the returned surface.
	  If for some reason the surface could not be placed in video memory,
	  it will not have the SDL::HWSURFACE flag set, and will be created in system
	  memory instead.

	  \param flags the flags to specify the kind of the surface.
	  \param width the width of the new surface.
	  \param height the height of the new surface.
	  \param depth the color depth of the new surface (bits per pixel).
	  \param Rmask, Gmask, Bmask, Amask the masks to determine the
	  pixel format.
	 */
        Surface (Uint32 flags, int width, int height, int depth,
        	 Uint32 Rmask = 0, Uint32 Gmask = 0, Uint32 Bmask = 0,
		 Uint32 Amask = 0);

	//! Allocate an empty RGB surface with given pixel format.
	/*!
	  This constructor is similar to SEL::Surface::Surface (flags, width,
	  height, depth, Rmask, Gmask, Bmask, Amask). The new surface will
	  have a pixel format identical to \a fmt except that the palette,
	  alpha value, and colorkey of \a fmt are ignored.
	  \param flags the flags to specify the kind of the surface.
	  \param width the width of the new surface.
	  \param height the height of the new surface.
	  \param fmt the pixel format of the new surface.
	  \sa Surface::Surface (flags, width, height, depth, Rmask, Gmask,
	  Bmask, Amask);
	 */
	Surface (Uint32 flags, int width, int height,
        	 const SDL::PixelFormat & fmt);

	//! Create a new RGB surface from the provided pixel data.
	/*!
	  The data stored in \a pixels is assumed to be of the depth
	  specified by \a depth.
	  \note The pixel data is not freed by the surface because
	  it is not it's property.
	  \param pixels the pixel data of the new surface.
	  \param width the width of the new surface.
	  \param height the height of the new surface.
	  \param depth the color depth of the new surface (bits per pixel).
	  \param pitch the length of each scanline in bytes.
	  \param Rmask, Gmask, Bmask, Amask the masks to determine the
	  pixel format.
	 */
	Surface (void *pixels, int width, int height, int depth, int pitch,
        	 Uint32 Rmask = 0, Uint32 Gmask = 0, Uint32 Bmask = 0,
                 Uint32 Amask = 0);

        //! Convert an existing surface to the specified pixel format.
	/*!
	  This creates a new surface of the specified format, and then
	  copies and maps the given surface to it so the blit of the
	  converted surface will be as fast as possible.
	  On any error an exception is thrown.
	  \param src the source surface
	  \param fmt the desired pixel format
	  \param flags specifies the kind of new surface.
	  \sa displayFormat ()
	 */
        static Surface *convertSurface (Surface *src,
        				const SDL::PixelFormat &fmt,
                                        Uint32 flags);

        //! Convert an existing surface to the specified pixel format.
	/*!
	  This creates a new surface of the specified format, and then
	  copies and maps the given surface to it so the blit of the
	  converted surface will be as fast as possible.
	  On any error an exception is thrown.
	  \param src the source surface
	  \param fmt the desired pixel format
	  \param flags specifies the kind of new surface.
	  \sa displayFormat ()
	 */
	static Surface *convertSurface (SDL::Surface *src,
        				const SDL::PixelFormat &fmt,
                                        Uint32 flags);

	//! Convert an existing surface to a format with alpha channel
	//! that's suitable for fast blitting to a surface with given
	//! pixel format.
	/*!
	  On any error throws an exception.
	  \param src the source surface
	  \param fmt the pixel format of the surface you want to blit to.
	 */
	static Surface *convertSurfaceAlpha (SDL::Surface *src,
					     const SDL::PixelFormat &fmt);

	//! Convert an existing surface to a format with alpha channel
	//! that's suitable for fast blitting to a surface with given
	//! pixel format.
	/*!
	  On any error throws an exception.
	  \param src the source surface
	  \param fmt the pixel format of the surface you want to blit to.
	 */
	static Surface *convertSurfaceAlpha (Surface *src,
					     const SDL::PixelFormat &fmt);

	//! Convert an existing surface to the display format.
	/*!
	  This function takes a surface and copies it to a new
	  surface of the pixel format and colors of the video
	  framebuffer, suitable for fast blitting onto the display
	  surface.
	  \note If you want to take advantage of hardware colorkey or
	  alpha blit accelleration, you should set the colorkey and
	  alpha value before calling this function.

	  On any error this function throws an exception.
	  \param src the source surface.
	 */
        static Surface *displayFormat (Surface *src);

	//! Convert an existing surface to the display format.
	/*!
	  This function takes a surface and copies it to a new
	  surface of the pixel format and colors of the video
	  framebuffer, suitable for fast blitting onto the display
	  surface.
	  \note If you want to take advantage of hardware colorkey or
	  alpha blit accelleration, you should set the colorkey and
	  alpha value before calling this function.

	  On any error this function throws an exception.
	  \param src the source surface.
	 */
        static Surface *displayFormat (SDL::Surface *src);

	//! Convert an existing surface to the display format with an alpha
	//! channel.
	/*!
	  This function takes a surface and copies it to a new surface of
	  the pixel format and colors of the video framebuffer (if possible),
	  suitable for fast alpha blitting onto the display surface.
	  The new surface will always have an alpha channel.
	  \note If you want to take advantage of hardware colorkey or
	  alpha blit accelleration, you should set the colorkey and
	  alpha value before calling this function.
	  On any error this function throws an exception.
	  \param src the source surface.
	 */
        static Surface *displayFormatAlpha (Surface *src);

	//! Convert an existing surface to the display format with an alpha
	//! channel.
	/*!
	  This function takes a surface and copies it to a new surface of
	  the pixel format and colors of the video framebuffer (if possible),
	  suitable for fast alpha blitting onto the display surface.
	  The new surface will always have an alpha channel.
	  \note If you want to take advantage of hardware colorkey or
	  alpha blit accelleration, you should set the colorkey and
	  alpha value before calling this function.
	  On any error this function throws an exception.
	  \param src the source surface.
	 */
        static Surface *displayFormatAlpha (SDL::Surface *src);

        //! Create a surface that will be a part of an existing one.
	/*!
	  This function creates a new surface that will be a part of
	  the parent surface. Any modification of the child surface's
	  framebuffer will render to the parent's framebuffer.
	  Parent's reference count will be increased by one on child's
	  creation and then decreased by one on child's destruction.
	  \note Only the framebuffer is shared. Each surface has it's own
	  palette, etc.

	  On any error this function throws an exception.
	  \param src the parent surface.
	  \param rect the part of the parent surface that the child will
	  contain.
	 */
        static Surface *createChildSurface (Surface *src,
        				    const SDL::Rect &rect);

	//! Load a surface from a seekable SDL data source (memory or file.)
	/*!
	  On any error throws an exception.
	  \return A new surface that contains the image.
	  \param src the source SDL::RWops.
	  \param freesrc whether to close and delete the source RWops after
	  loading.
	 */
	static Surface *loadBMP (SDL::RWops *src, bool freesrc = false);

	//! Load a surface from a seekable SEL data source (memory or file.)
	/*!
	  On any error throws an exception.
	  \return A new surface that contains the image.
	  \param src the source RWops.
	 */
	static Surface *loadBMP (SEL::RWops & src);

	//! Load a surface from a file
	/*!
	  On any error throws an exception.
	  \return A new surface that contains the image.
	  \param filename the name of the image file
	 */
	static Surface *loadBMP (const std::string &filename);
        //@}

	//! \name Saving surface contents
	//@{

	//! Save the surface to a seekable SDL data source (memory or file).
	/*!
	  \return true, or false on error.
	  \param dst the destination SDL::RWops.
	  \param freedst whether to close and free the source after saving.
	 */
	bool saveBMP (SDL::RWops *dst, bool freedst = false);

	//! Save the surface to a seekable SEL data source (memory or file).
	/*!
	  \return true, or false on error.
	  \param dst the destination RWops.
	 */
	bool saveBMP (SEL::RWops & dst);

	//! Save the surface to a file.
	/*!
	  \return true, or false on error.
	  \param filename the name of the destination file.
	 */
	bool saveBMP (const std::string &filename);

	//!

	//@}

        //! \name Surface conversion
        //@{

        //! Convert the surface to a specified pixel format.
	/*!
	  This converts an existing surface to a different pixel format.
	  The \a flags determine the kind of surface after conversion.

	  On any error this function throws an exception.
	  \param fmt the desired pixel format
	  \param flags the flags of the surface after conversion.
	  \sa Surface::Surface (Uint8 flags, int width, int height, int depth, Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask);
	 */
        void convertSurface (const SDL::PixelFormat &fmt, Uint32 flags);

	//! Convert surface to a format with alpha channel that's suitable
	//! for fast blitting to a surface with given pixel format.
	/*!
	  \param fmt the pixel format of the surface you want to blit to.
	 */
	void convertSurfaceAlpha (const SDL::PixelFormat &fmt);

	//! Convert the surface to the display format.
	/*!
	  This function converts the surface to the display format which is
	  suitable for fast blitting onto to display framebuffer.
	  \note If you want to take advantage of hardware colorkey or
	  alpha blit accelleration, you should set the colorkey and
	  alpha value before calling this function.

	  On any error this function throws an exception.
	 */

        void displayFormat ();

	//! Convert the surface to the display format with an alpha channel.
	/*!
	  This function converts the surface to the display format which is
	  suitable for fast alpha blitting onto to display framebuffer.
	  \note If you want to take advantage of hardware colorkey or
	  alpha blit accelleration, you should set the colorkey and
	  alpha value before calling this function.

	  On any error this function throws an exception.
	 */
	void displayFormatAlpha ();
        //@}

        //! \name Locking and unlocking
        //@{

        //! Return true if the surface needs to be locked before access.
        bool mustLock () const		{ return SDL::MUSTLOCK (m_surface); }

        //! Lock the surface.
	/*!
	  The lock () function sets up a surface for directly accessing the
	  pixels. Between calls to Surface::lock () / Surface::unlock (),
	  you can write to and read from Surface::pixels (), using the
	  pixel format. Once you are done accessing the surface, you should
	  use Surface::unlock () to release it.

	  \note Not all surfaces require locking. If the Surface::mustLock ()
	  function returns false, then you can read and write to the surface
	  at any time, and the pixel format of the surface will not change. In
	  particular, if the SDL::HWSURFACE flag is not given when initializing
	  the display surface, you will not need to lock the display surface
	  before accessing it.

	  \note Since SDL version 1.1.8 locking is recursive (e.g. if you call
	  Surface::lock () twice, you also need to call Surface::unlock ()
	  twice to release the surface).

	  \warning No operating system or library calls should be made between
	  lock / unlock pairs, as critical system locks may be held during
	  this time.

	  \return true, or false if the surface couldn't be locked.
	 */
        bool lock () const;

        //! Release the previously locked surface.
	void unlock () const;
        //@}

        //! \name Color mapping
        //@{

        //! Map a RGB triple to an opaque pixel value for a surface's pixel format.
	/*!
	  Maps the RGB color value to this surface's pixel format and returns
	  the pixel value as a 32-bit int.

	  If the format has a palette (8-bit) the index of the closest
	  matching color in the palette will be returned.

	  If the specified pixel format has an alpha component it will be
	  returned as all 1 bits (fully opaque).

	  \return A pixel value best approximating the given RGB color
	  value for a given pixel format. If the pixel format bpp (color
	  depth) is less than 32-bpp then the unused upper bits of the
	  return value can safely be ignored (e.g., with a 16-bpp format
	  the return value can be assigned to a Uint16, and similarly a
	  Uint8 for an 8-bpp format).

	  \param r, g, b the red, green and blue components of the color.
	  \sa mapRGBA, getRGB, getRGBA
	 */
        Uint32 mapRGB (Uint8 r, Uint8 g, Uint8 b);

        //! Maps a RGBA quadruple to a pixel value for a surface's pixel format.
	/*!
	  Maps the RGB color value to this surface's pixel format and returns
	  the pixel value as a 32-bit int.

	  If the format has a palette (8-bit) the index of the closest
	  matching color in the palette will be returned.

	  If the specified pixel format has no alpha component the alpha
      	  value will be ignored (as it will be in formats with a palette).

	  \return A pixel value best approximating the given RGB color
	  value for a given pixel format. If the pixel format bpp (color
	  depth) is less than 32-bpp then the unused upper bits of the
	  return value can safely be ignored (e.g., with a 16-bpp format
	  the return value can be assigned to a Uint16, and similarly a
	  Uint8 for an 8-bpp format).

	  \param r, g, b, a the red, green, blue and alpha components of the color.
	  \sa mapRGB, getRGB, getRGBA
	 */
        Uint32 mapRGBA (Uint8 r, Uint8 g, Uint8 b, Uint8 a);

        //! Map a pixel value into the RGB components for a surface's pixel format.
	/*!
	  This function uses the entire 8-bit [0..255] range when
	  converting color components from pixel formats with less than
	  8-bits per RGB component (e.g., a completely white pixel in
	  16-bit RGB565 format would return [0xff, 0xff, 0xff] not [0xf8,
	  0xfc, 0xf8]).

	  \param pixel the pixel value.
	  \param r, g, b references to the integers where the RGB
	  result will be stored.

	  \sa GetRGBA, MapRGB, MapRGBA
	 */
        void getRGB (Uint32 pixel, Uint8 &r, Uint8 &g, Uint8 &b);

	//! Map a pixel value into the RGBA components for a surface's pixel format.
	/*!
	  This function uses the entire 8-bit [0..255] range when
	  converting color components from pixel formats with less than
	  8-bits per RGB component (e.g., a completely white pixel in
	  16-bit RGB565 format would return [0xff, 0xff, 0xff] not [0xf8,
	  0xfc, 0xf8]).

	  \note If the surface has no alpha component, the alpha will be
	  returned as 0xff (100% opaque).

	  \param pixel the pixel value.
	  \param r, g, b, a references to the integers where the RGBA
	  result will be stored.
	 */
        void getRGBA (Uint32 pixel, Uint8 &r, Uint8 &g, Uint8 &b, Uint8 &a);
        //@}

        //! \name Alpha and color key
        //@{

        //! Set the alpha value for the entire surface.
	/*!
	  This function sets the alpha value for the entire surface, as
	  opposed to using the alpha component of each pixel.
	  - If \a flag is 0, alpha blending is disabled for the surface.
	  - If \a flag is SDL::SRCALPHA, alpha blending is enabled for the
	  surface.
	  - If \a flag is OR'd with SDL::RLEACCEL, the function requests
	  RLE acceleration for the surface. If the SDL::RLEACCEL is not
	  specified, the RLE acceleration will be removed.

	  \param alpha per surface alpha. This value measures the range
	  of transparency of the surface, 0 ( = SDL::ALPHA_TRANSPARENT)
	  being completely transparent to 255 ( = SDL::ALPHA_OPAQUE) being
	  completely opaque. An \a alpha value of 255 causes blits to be
	  opaque, the source pixels copied to the destination (the default).

	  \param flag the flags as described above.

	  \note The per-surface alpha can be combined with colorkey
	  transparency.
	  \note The per-surface \a alpha value of 128 is considered a
	  special case and it's optimized, so it's much faster than other
	  per-surface values.

	  \return true, or false on error
	 */
        bool setAlpha (Uint8 alpha, Uint32 flag = SDL::SRCALPHA);

        //! Set the alpha blending policy for the surface.
	/*!
	  This function sets the alpha blending policy for the surface.
	  - If \a flag is 0, alpha blending is disabled for the surface.
	  - If \a flag is SDL::SRCALPHA, alpha blending is enabled for the
	  surface.
	  - If \a flag is OR'd with SDL::RLEACCEL, the function requests
	  RLE acceleration for the surface. If the SDL::RLEACCEL is not
	  specified, the RLE acceleration will be removed.

	  \param flag the flags as described above.

	  \note This function does not modify the per surface alpha value.

	  \return true, or false on error
	 */
        bool setAlphaFlags (Uint32 flag = SDL::SRCALPHA);


	//! Set the color key (transparent pixel) in a blittable surface
	//! and enable or disable RLE blit acceleration.
	/*!
	  RLE acceleration can substantially speed up blitting of images
	  with large horizontal runs of transparent pixels (i.e., pixels
	  that match the \a key value). The key must be of the same pixel
	  format as the surface, MapRGB() is often useful for obtaining an
	  acceptable value.

	  - If the flag is SDL::SRCCOLORKEY then key is the transparent
	  pixel value in the source image of a blit.
	  - If the flag is OR'd with SDL::RLEACCEL then the surface
	  will be blitted using the RLE accelleration. The surface is
	  actually first time encoded for the RLE accelleration when
	  Surface::blit () or Surface::displayFormat () is called.
	  - If the flag is 0, this function clears any current color key.

	  \returns true, or false on error.
	  \param key the pixel value for the color key
	  \param flag the flags as described above.
	*/
        bool setColorKey (Uint32 key, Uint32 flag = SDL::SRCCOLORKEY);

	//! Set the color key (transparent pixel) policy for a blittable
	//! surface and enable or disable RLE blit acceleration.
	/*!
	  RLE acceleration can substantially speed up blitting of images
	  with large horizontal runs of transparent pixels (i.e., pixels
	  that match the \a key value). The key must be of the same pixel
	  format as the surface, MapRGB() is often useful for obtaining an
	  acceptable value.

	  - If the flag is SDL::SRCCOLORKEY then key is the transparent
	  pixel value in the source image of a blit.
	  - If the flag is OR'd with SDL::RLEACCEL then the surface
	  will be blitted using the RLE accelleration. The surface is
	  actually first time encoded for the RLE accelleration when
	  Surface::blit () or Surface::displayFormat () is called.
	  - If the flag is 0, this function clears any current color key.

	  \returns true, or false on error.
	  \param flag the flags as described above.
	*/
        bool setColorKeyFlags (Uint32 flag = SDL::SRCCOLORKEY);
        //@}

        //! \name Clipping
        //@{

	//! Reset the clipping rectangle for the surface.
	/*!
	   This function sets the clipping rectangle to the full size
	   of the surface.
	   \sa setClipRect (), clipRect (), blit ()
	 */
	void resetClipRect ();

        //! Set the clipping rectangle for the surface.
	/*!
	  Sets the clipping rectangle for a surface. When this surface is
	  the destination of a blit, only the area within the clip
	  rectangle will be drawn into.

	  \param x, y, w, h the coordinates and dimensions of the clipping
	  rectangle.

	  \return If the clip rectangle doesn't intersect the surface,
	  the function will return false and blits will be completely clipped.
	  Otherwise the function returns true and blits to the surface will
	  be clipped to the intersection of the surface area and the clipping
	  rectangle.

	 \note Blits are automatically clipped to the edges of the source
	  and destination surface.
         */
        bool setClipRect (Sint16 x, Sint16 y, Uint16 w, Uint16 h);

        //! Set the clipping rectangle for the surface.
	/*!
	  Sets the clipping rectangle for a surface. When this surface is
	  the destination of a blit, only the area within the clip
	  rectangle will be drawn into.

	  \param rect The rectangle pointed to by rect will be clipped to
	  the edges of the surface so that the clip rectangle for a
	  surface can never fall outside the edges of the surface.

	  \return If the clip rectangle doesn't intersect the surface,
	  the function will return false and blits will be completely clipped.
	  Otherwise the function returns true and blits to the surface will
	  be clipped to the intersection of the surface area and the clipping
	  rectangle.

	 \note Blits are automatically clipped to the edges of the source
	  and destination surface.
         */
        bool setClipRect (SDL::Rect &rect);

        //! Return the clipping rectangle.
        SDL::Rect clipRect () const;
        //@}

        //! \name Palette manipulation
        //@{

        //! Set a portion of the color map.
	/*!
	  Sets a portion of the colormap of the 8-bit surface.
	  \return
	  If surface it not a palettized surface, this function does nothing,
	  returning false. I all of the colors were set as passed to
	  Surface::setColors (), it will return true. If not all the color
	  entries were set exactly as given, it will return false, and you
	  should look at the surface palette to determine the actual color
	  palette.

	  \note
	  If surface is the surface associated with the current display,
	  the display colormap will be updated with the requested colors.
	  If SDL::HWPALETTE flag was set on video mode setting,
	  Surface::setColors will always return true, and the palette
	  is guaranteed to be set the way you desire, even if the window
	  colormap has to be warped or run under emulation.

	  \param colors the array of SDL::Color.
	  \param firstcolor the index of the first color that should be set.
	  \param ncolors the number of colors to be set.
	 */
        bool setColors (SDL::Color *colors, int firstcolor, int ncolors);

        //! Set a portion of the color map.
	/*!
	  Sets a portion of the colormap for a given 8-bit surface.

	  The \a flags is one or both of:
	  - SDL::LOGPAL set logical palette, which controls how blits are
	  mapped to/from the surface.
	  - SDL::PHYSPAL set physical palette, which controls how pixels look
	  on the screen.

	  Only screens have physical palette. Separate change of physical/
	  logical palette is only possible if the screen has SDL::HWPALETTE
	  set.

	  \return true if all colors could be set as requested, and false
	  otherwise.

	  \note Surface::setColors () is equivalent to calling this function
	  with \a flags = (SDL::LOGPAL | SDL::PHYSPAL).

	  \param flags the flags as described above.
	  \param colors the array of SDL::Color.
	  \param firstcolor the index of the first color that should be set.
	  \param ncolors the number of colors to be set.
	 */
        bool setPalette (int flags, SDL::Color *colors, int firstcolor,
        		int ncolors);
        //@}

        //! \name Blitting
        //@{

	//! Fast blit the whole source surface onto this surface at the
	//! specified coordinates.
	/*!
	  The source surface will be blitted to this surface.
	  If the source surface is larger than the destination,
	  clipping will occur. No scaling will be performed. Blitting
	  should not be used on a locked surface. The entire surface will
	  be copied to this surface using this function.

	  \return If the blit is successful, it returns 0, otherwise it
	  returns -1. If either of the surfaces were in video memory,
	  and the blit returns -2, the video memory was lost. It should
	  be reloaded with artwork and re-blitted.

	  \param src the surface to blit from.
	  \param dst_x, dst_y the destination coordinates.
	 */

        int blit (Surface *src, Sint16 dst_x, Sint16 dst_y);

	//! Fast blit the specified area part of the source surface onto
	//! this surface at the specified coordinates.
	/*!
	  The choosen rectangle of the source surface will be blitted to
	  this surface. If the source area is larger than the destination,
	  clipping will occur. No scaling will be performed. Blitting
	  should not be used on a locked surface. The final blit
	  rectangle is saved in \a dstrect after all clipping is performed
	  (\a srcrect is not modified).

	  \return If the blit is successful, it returns 0, otherwise it
	  returns -1. If either of the surfaces were in video memory,
	  and the blit returns -2, the video memory was lost. It should
	  be reloaded with artwork and re-blitted.

	  \param src the surface to blit from.
	  \param srcrect the rectangular area to copy from the source
	   surface.
	  \param dstrect the destination coordinates. Only the position
	   is used (i.e width and height are ignored).
	  \note if \a srcrect or \a dstrect are NULL the whole surface
	   will be blitted.

	  The blit semantics for surfaces with and without
	  alpha and colorkey are defined as follows:
	  \verbatim
	   RGBA->RGB:
	       SDL::SRCALPHA set:
	        alpha-blend (using alpha-channel).
	        SDL::SRCCOLORKEY ignored.
	       SDL::SRCALPHA not set:
	        copy RGB.
	        if SDL::SRCCOLORKEY set, only copy the pixels matching the
	        RGB values of the source colour key, ignoring alpha in the
	        comparison.

	   RGB->RGBA:
	       SDL::SRCALPHA set:
	        alpha-blend (using the source per-surface alpha value);
	        set destination alpha to opaque.
	       SDL::SRCALPHA not set:
	        copy RGB, set destination alpha to opaque.
	       both:
	        if SDL::SRCCOLORKEY set, only copy the pixels matching the
	        source colour key.

	   RGBA->RGBA:
	       SDL::SRCALPHA set:
	        alpha-blend (using the source alpha channel) the RGB values;
	        leave destination alpha untouched.
	        SDL::SRCCOLORKEY ignored.
	       SDL::SRCALPHA not set:
	        copy all of RGBA to the destination.
	        if SDL::SRCCOLORKEY set, only copy the pixels matching the
	        RGB values of the source colour key, ignoring alpha in the
	        comparison.

	   RGB->RGB:
	       SDL::SRCALPHA set:
	        alpha-blend (using the source per-surface alpha value).
	       SDL::SRCALPHA not set:
	        copy RGB.
	       both:
	        if SDL::SRCCOLORKEY set, only copy the pixels matching the
	        source colour key.
	  \endverbatim
	 */
        int blit (Surface *src, SDL::Rect *srcrect = NULL,
        	  SDL::Rect *dstrect = NULL);

	//! Fast blit the specified area part of the source surface onto
	//! this surface at the specified coordinates.
	/*!
	  The choosen rectangle of the source surface will be blitted to
	  this surface. If the source area is larger than the destination,
	  clipping will occur. No scaling will be performed. Blitting
	  should not be used on a locked surface. The final blit
	  rectangle is saved in \a dstrect after all clipping is performed
	  (\a srcrect is not modified).

	  \return If the blit is successful, it returns 0, otherwise it
	  returns -1. If either of the surfaces were in video memory,
	  and the blit returns -2, the video memory was lost. It should
	  be reloaded with artwork and re-blitted.

	  \param src the surface to blit from.
	  \param srcrect the rectangular area to copy from the source
	   surface.
	  \param dstrect the destination coordinates. Only the position
	   is used (i.e width and height are ignored).
	 */
        int blit (Surface *src, SDL::Rect &srcrect, SDL::Rect &dstrect);
	//@}

        //! \name Filling rectangles
        //@{

	//! Fill the part of the surface with the given color.
	/*!
	  The rectangle is clipped to the surface clip area.
	  \return true, or false on error.
	  \param rect the part of the surface to be filled.
	  \param color the pixel value.
	 */
        bool fillRect (SDL::Rect rect, Uint32 color);

	//! Fill the part of the surface with the given color.
	/*!
	  The rectangle is clipped to the surface clip area.
	  \return true, or false on error.
	  \param rect the part of the surface to be filled.
	  \param r, g, b, a the components of the color.

	  \note This function does no alpha blending. If the surface is
	   RGB, the alpha component is ignored.
	 */
        bool fillRect (SDL::Rect rect, Uint8 r, Uint8 g, Uint8 b,
        	       Uint8 a = SDL::ALPHA_OPAQUE);

	//! Fill the part of the surface with the given color.
	/*!
	  The rectangle is clipped to the surface clip area, and
	  the final fill rectangle is saved in the passed rectangle.
	  \return true, or false on error.
	  \param rect the part of the surface to be filled.
	  \param color the pixel value.
	 */

	bool fillRect (SDL::Rect *rect, Uint32 color);

	//! Fill the part of the surface with the given color.
	/*!
	  The rectangle is clipped to the surface clip area, and
	  the final fill rectangle is saved in the passed rectangle.
	  \return true, or false on error.
	  \param rect the part of the surface to be filled.
	  \param r, g, b, a the components of the color.

	  \note This function does no alpha blending. If the surface is
	   RGB, the alpha component is ignored.
	 */
	bool fillRect (SDL::Rect *rect, Uint8 r, Uint8 g, Uint8 b,
        	       Uint8 a = SDL::ALPHA_OPAQUE);

	//! Fill the entire surface with the given color.
	/*!
	  \return true, or false on error.
	  \param color the pixel value.
	 */
        bool fill (Uint32 color);

	//! Fill the entire surface with the given color.
	/*!
	  \return true, or false on error.
	  \param r, g, b, a the components of the color.
	  \note This function does no alpha blending. If the surface is
	   RGB, the alpha component is ignored.
	 */
        bool fill (Uint8 r, Uint8 g, Uint8 b, Uint8 a = SDL::ALPHA_OPAQUE);
        //@}
protected:
	//! The wrapped SDL::Surface structure.
        SDL::Surface *m_surface;

	//! The parent surface.
	/*! This is NULL if surface has no parent. */
        SEL::Surface *m_parent;
	bool m_auto_free;

        void wrapSurface (SDL::Surface *wrap_me, bool auto_free = true);
        void releaseSurface ();

        Surface () { }
};

//! The video framebuffer surface.
/*!
  This class represents the actual video framebuffer memory. If you
  are using hardware video support, the actual memory is stored on the
  graphics card.

  You shouldn't create more than one instance of Display at the
  same time.
 */
class Display : public Surface
{
public:
	//! Set up a video mode with the specified width, height
	//! and bits-per-pixel.
	/*!
	  If \a bpp is 0, it is treated as the current display bits per pixel.

	  If SDL::ANYFORMAT is set in \a flags, the SDL library will try to set
	  the requested bits-per-pixel, but will return whatever video
	  pixel format is available. The default is to emulate the requested
	  pixel format if it is not natively available.

	  If SDL::HWSURFACE is set in \a flags, the video surface will be
	  placed in video memory, if possible, and you may have to call
	  Surface::lock () in order to access the raw framebuffer.
	  Otherwise, the video surface will be created in system memory.

	  If SDL::ASYNCBLIT is set in \a flags, SDL will try to perform
	  rectangle updates asynchronously, but you must always lock
	  before accessing pixels. SDL will wait for updates to complete
	  before returning from the lock.

	  If SDL::HWPALETTE is set in \a flags, the SDL library will guarantee
	  that the colors set by Surface::setColors() will be the colors you
	  get. Otherwise, in 8-bit mode, Surface::setColors() may not be able
	  to set all of the colors exactly the way they are requested, and you
	  should look at the video surface structure to determine the actual
	  palette. If SDL cannot guarantee that the colors you request can be
	  set, i.e. if the colormap is shared, then the video surface may be
	  createdunder emulation in system memory, overriding the
	  SDL::HWSURFACE flag.

	  If SDL::FULLSCREEN is set in \a flags, the SDL library will try
	  to set a fullscreen video mode. The default is to create a windowed
	  mode if the current graphics system has a window manager. If the SDL
	  library is able to set a fullscreen video mode, this flag will be
	  set in the surface that is returned.

	  If SDL::DOUBLEBUF is set in \a flags, the SDL library will try to
	  set up two surfaces in video memory and swap between them when you
	  call Display::flip (). This is usually slower than the normal
	  single-buffering scheme, but prevents "tearing" artifacts caused
	  by modifying video  memory while the monitor is refreshing.
	  It should only be used by  applications that redraw the entire
	  screen on every update.

	  If SDL::RESIZABLE is set in \a flags, the SDL library will allow
	  the window manager, if any, to resize the window at runtime.
	  When this occurs, SDL will send a SDL::VIDEORESIZE event to you
	  application, and you must respond to the event by re-calling
	  Display::setVideoMode () with the requested size
	  (or another size that suits the application).

	  If SDL::NOFRAME is set in \a flags, the SDL library will create
	  a window without any title bar or frame decoration.  Fullscreen
	  video modes have this flag set automatically.

	  \return
	  This function returns the video framebuffer surface, or throws
	  an exception if it fails.

	  \note
	  If you rely on functionality provided by certain video flags,
	  check the flags of the returned surface to make sure that
	  functionality is available. SDL will fall back to reduced
	  functionality if the exact flags you wanted are not available.

	  \param w the desired width.
	  \param h the desired height.
	  \param bpp the desired color depth (bits per pixel)
	  \param flags the flags as described above.
	 */
        Display (int w, int h, int bpp, Uint32 flags);

	//! Set up a video mode with the specified width, height
	//! and bits-per-pixel.
	/*!
	  This actually re-sets the video mode. This is primary intented
	  to call on SDL::VIDEORESIZE event or when the display size
	  has to be changed.

	  For more information see the SEL::Display::Display ()
	  constructor.
	 */
	void setVideoMode (int w, int h, int bpp, Uint32 flags);

        //! \name updating the screen contents
        //@{

        //! Flip the front and back buffer.
	/*!
	  On hardware that supports double-buffering, this function sets
	  up a flip and returns.  The hardware will wait for vertical retrace,
	  and then swap video buffers before the next video surface blit
	  or lock will return. On hardware that does not support
	  double-buffering, this is equivalent to calling
	  Display::updateRect();

	  \note The SDL::DOUBLEBUF flag must have been passed to
	  Display::setVideoMode() when setting the video mode for this function
	  to perform hardware flipping.
	  \return true, or false if there was an error.
	 */
        bool flip ();

        //! Make sure that the given rectangle is updated on the screen.
	/*!
	  Called without arguments refreshes the whole screen.

	  This should not be called while the display is locked.
	  \param x, y, w, h the place on the screen to be updated.
	 */
        void updateRect (Sint32 x = 0, Sint32 y = 0,
        		 Sint32 w = 0, Sint32 h = 0);

        //! Make sure that the given rectangle is updated on the screen.
	/*!
	  This should not be called while the display is locked.
	  \param rect the place on the screen to be updated.
	 */
	void updateRect (const SDL::Rect & rect);

	//! Make sure the given list of rectangles is updated on the display
	/*!
	  This function should not be called if the display is locked!

	  \note It is adviced to call this function only once per frame,
	  since each call has some processing overhead. This is no
	  restriction since you can pass any number of rectangles each
	  time.

	  The rectangles are not automatically merged or checked for
	  overlap. In general, the programmer can use his knowledge about
	  his particular rectangles to merge them in an efficient way, to
	  avoid overdraw.

	  \param numrects the number of rectangles in the array.
	  \param rects the array of rectangles to update.
	  \sa updateRect ()
	 */
        void updateRects (int numrects, SDL::Rect *rects);
        //@}
};

//////////////////////////////////////////////////////////////////
//////////////////////// INLINE FUNCTIONS ////////////////////////
//////////////////////////////////////////////////////////////////

inline
Surface::Surface (SDL::Surface *wrap_me, bool auto_free)
{
	wrapSurface (wrap_me, auto_free);
}

inline
Surface::~Surface ()
{
	releaseSurface ();
}

inline
Surface::Surface (Uint32 flags, int width, int height, int depth,
        	  Uint32 Rmask, Uint32 Gmask, Uint32 Bmask,
		  Uint32 Amask)
{
	SDL::Surface *surface =
        	SDL::CreateRGBSurface (flags, width, height, depth,
                		       Rmask, Gmask, Bmask, Amask);
	wrapSurface (surface);
}

inline
Surface::Surface (Uint32 flags, int width, int height,
		  const SDL::PixelFormat & fmt)
{
	SDL::Surface *surface =
        	SDL::CreateRGBSurface (flags, width, height,
                		       fmt.BitsPerPixel,
                                       fmt.Rmask, fmt.Gmask,
                                       fmt.Bmask, fmt.Amask);
        wrapSurface (surface);
}

inline
Surface::Surface (void *pixels, int width, int height, int depth, int pitch,
		  Uint32 Rmask, Uint32 Gmask, Uint32 Bmask, Uint32 Amask)
{
	SDL::Surface *surface =
        	SDL::CreateRGBSurfaceFrom (pixels, width, height, depth,
                			   pitch, Rmask, Gmask, Bmask,
                                           Amask);

	wrapSurface (surface);
}

inline Surface *
Surface::convertSurface (Surface * src, const SDL::PixelFormat & fmt, Uint32 flags)
{
	SDL::PixelFormat fmt_ = fmt;

	// (if the `src' is NULL, throw an exception)
	return_val_if_fail (src != NULL, new Surface (NULL));

	SDL::Surface *surface =
        	SDL::ConvertSurface (src->surface (), &fmt_, flags);

	return new Surface (surface);
}

inline Surface *
Surface::convertSurface (SDL::Surface *src, const SDL::PixelFormat & fmt,
                         Uint32 flags)
{
	SDL::PixelFormat fmt_ = fmt;

	// (if the src' is NULL, throw an exception)
	return_val_if_fail (src != NULL, new Surface (NULL));

	SDL::Surface *surface =
        	SDL::ConvertSurface (src, &fmt_, flags);

	return new Surface (surface);
}

inline Surface *
Surface::displayFormat (Surface *src)
{
	return_val_if_fail (src != NULL, new Surface (NULL));

	return new Surface (SDL::DisplayFormat (src->surface ()));
}

inline Surface *
Surface::displayFormat (SDL::Surface *src)
{
	return_val_if_fail (src != NULL, new Surface (NULL));

	return new Surface (SDL::DisplayFormat (src));
}

inline Surface *
Surface::displayFormatAlpha (Surface *src)
{
	return_val_if_fail (src != NULL, new Surface (NULL));

	return new Surface (SDL::DisplayFormatAlpha (src->surface ()));
}

inline Surface *
Surface::displayFormatAlpha (SDL::Surface *src)
{
	return_val_if_fail (src != NULL, new Surface (NULL));

	return new Surface (SDL::DisplayFormatAlpha (src));
}

inline Surface *
Surface::loadBMP (SDL::RWops *src, bool freesrc)
{
	SDL::Surface *surface = SDL::LoadBMP_RW (src, freesrc);

	return new Surface (surface);
}

inline Surface *
Surface::loadBMP (SEL::RWops & src)
{
	return loadBMP (src.rwops (), false);
}

inline Surface *
Surface::loadBMP (const std::string &filename)
{
	SDL::Surface *surface = SDL::LoadBMP (filename.c_str ());
	return new Surface (surface);
}

inline bool
Surface::saveBMP (SDL::RWops *dst, bool freedst)
{
	return SDL::SaveBMP_RW (m_surface, dst, freedst) == 0;
}

inline bool
Surface::saveBMP (SEL::RWops & dst)
{
	return saveBMP (dst.rwops(), false) == 0;
}

inline bool
Surface::saveBMP (const std::string &filename)
{
	return SDL::SaveBMP (m_surface, filename.c_str ()) == 0;
}

inline void
Surface::convertSurface (const SDL::PixelFormat &fmt, Uint32 flags)
{
	SDL::PixelFormat fmt_ = fmt;
        SDL::Surface *surface =
        	SDL::ConvertSurface (m_surface, &fmt_, flags);
	releaseSurface ();
        wrapSurface (surface);
}

inline void
Surface::displayFormat ()
{
	SDL::Surface *surface = SDL::DisplayFormat (m_surface);
	releaseSurface ();
        wrapSurface (surface);
}

inline void
Surface::displayFormatAlpha ()
{
	SDL::Surface *surface = SDL::DisplayFormatAlpha (m_surface);
        releaseSurface ();
        wrapSurface (surface);
}

inline bool
Surface::lock () const
{
	if (SDL::MUSTLOCK(m_surface))
        	return SDL::LockSurface (m_surface) == 0;
	return false;
}

inline void
Surface::unlock () const
{
	SDL::UnlockSurface (m_surface);
}

inline Uint32
Surface::mapRGB (Uint8 r, Uint8 g, Uint8 b)
{
	return SDL::MapRGB (format (), r, g, b);
}

inline Uint32
Surface::mapRGBA (Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
	return SDL::MapRGBA (format (), r, g, b, a);
}

inline void
Surface::getRGB (Uint32 pixel, Uint8 &r, Uint8 &g, Uint8 &b)
{
	return SDL::GetRGB (pixel, format (), &r, &g, &b);
}

inline void
Surface::getRGBA (Uint32 pixel, Uint8 &r, Uint8 &g, Uint8 &b, Uint8 &a)
{
	return SDL::GetRGBA (pixel, format (), &r, &g, &b, &a);
}

inline bool
Surface::setAlpha (Uint8 alpha, Uint32 flag)
{
	return SDL::SetAlpha (m_surface, flag, alpha) == 0;
}

inline bool
Surface::setAlphaFlags (Uint32 flag)
{
	return SDL::SetAlpha (m_surface, flag, m_surface->format->alpha) == 0;
}

inline bool
Surface::setColorKey (Uint32 key, Uint32 flag)
{
	return SDL::SetColorKey (m_surface, flag, key) == 0;
}

inline bool
Surface::setColorKeyFlags (Uint32 flag)
{
	return SDL::SetColorKey (m_surface, flag,
				 m_surface->format->colorkey) == 0;
}

inline void
Surface::resetClipRect ()
{
	SDL::SetClipRect (m_surface, NULL);
}

inline bool
Surface::setClipRect (Sint16 x, Sint16 y, Uint16 w, Uint16 h)
{
	SEL::Rect rect (x, y, w, h);
        return setClipRect (rect);
}

inline bool
Surface::setClipRect (SDL::Rect &rect)
{
	return SDL::SetClipRect (m_surface, &rect);
}

inline SDL::Rect
Surface::clipRect () const
{
	SDL::Rect rect;
        SDL::GetClipRect (m_surface, &rect);
        return rect;
}

inline bool
Surface::setColors (SDL::Color *colors, int firstcolor, int ncolors)
{
	return SDL::SetColors (m_surface, colors, firstcolor, ncolors);
}

inline bool
Surface::setPalette (int flags, SDL::Color *colors, int firstcolor,
       	             int ncolors)
{
        return SDL::SetPalette (m_surface, flags, colors, firstcolor,
				ncolors);
}

inline int
Surface::blit (Surface *src, Sint16 dst_x, Sint16 dst_y)
{
        SEL::Rect dest (dst_x, dst_y, src->surface()->w, src->surface()->h);
        return blit (src, NULL, &dest);
}

inline int
Surface::blit (Surface *src, SDL::Rect *srcrect, SDL::Rect *dstrect)
{
	return SDL::BlitSurface (src->surface (), srcrect, m_surface, dstrect);
}

inline int
Surface::blit (Surface *src, SDL::Rect &srcrect, SDL::Rect &dstrect)
{
	return SDL::BlitSurface (src->surface (), &srcrect,
				 m_surface, &dstrect);
}

inline bool
Surface::fillRect (SDL::Rect rect, Uint32 color)
{
    return SDL::FillRect (m_surface, &rect, color) == 0;
}

inline bool
Surface::fillRect (SDL::Rect rect, Uint8 r, Uint8 g, Uint8 b,
                   Uint8 a)
{
        return SDL::FillRect (m_surface, &rect, mapRGBA (r, g, b, a)) == 0;
}

inline bool
Surface::fillRect (SDL::Rect *rect, Uint32 color)
{
    return SDL::FillRect (m_surface, rect, color) == 0;
}

inline bool
Surface::fillRect (SDL::Rect *rect, Uint8 r, Uint8 g, Uint8 b,
                   Uint8 a)
{
        return SDL::FillRect (m_surface, rect, mapRGBA (r, g, b, a)) == 0;
}

inline bool
Surface::fill (Uint32 color)
{
	return SDL::FillRect (m_surface, NULL, color) == 0;
}

inline bool
Surface::fill (Uint8 r, Uint8 g, Uint8 b, Uint8 a)
{
	return SDL::FillRect (m_surface, NULL, mapRGBA (r, g, b, a)) == 0;
}

//////////////////////////////////////////////////////////
//// DISPLAY SURFACE /////////////////////////////////////
//////////////////////////////////////////////////////////

inline bool
Display::flip ()
{
        return SDL::Flip (m_surface) == 0;
}

inline void
Display::updateRect (Sint32 x, Sint32 y, Sint32 w, Sint32 h)
{
	SDL::UpdateRect (m_surface, x, y, w, h);
}

inline void
Display::updateRect (const SDL::Rect &rect)
{
	SDL::UpdateRect (m_surface, rect.x, rect.y, rect.w, rect.h);
}

inline void
Display::updateRects (int numrects, SDL::Rect *rects)
{
	SDL::UpdateRects (m_surface, numrects, rects);
}

} // namespace SEL

#endif // __sel_surface_h__
